package com.coding4play.mqtt.store.util;

import com.coding4play.mqtt.common.entity.session.ChannelSession;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.mqtt.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;


public class SessionMap {

    private static final Logger LOGGER = LoggerFactory.getLogger(SessionMap.class);

    public static Map<String, Object> transPublishToMapBeta(ChannelSession store) {

        Map<String, Object> sessionStore = new HashMap();
        sessionStore.put("clientId", store.getClientId());
        sessionStore.put("channelId", store.getChannelId());
        sessionStore.put("cleanSession", store.getCleanSession());
        sessionStore.put("brokerId", store.getBrokerId());
        sessionStore.put("expire", store.getExpire());
        MqttPublishMessage msg = store.getWillMessage();
        try {
            if (null != msg) {
                addv(sessionStore, "payload", Base64.getEncoder().encodeToString(msg.payload().array()));
                addv(sessionStore, "messageType", msg.fixedHeader().messageType().value());
                addv(sessionStore, "isDup", msg.fixedHeader().isDup());
                addv(sessionStore, "qosLevel", msg.fixedHeader().qosLevel().value());
                addv(sessionStore, "isRetain", msg.fixedHeader().isRetain());
                addv(sessionStore, "remainingLength", msg.fixedHeader().remainingLength());
                addv(sessionStore, "topicName", msg.variableHeader().topicName());
                addv(sessionStore, "packetId", msg.variableHeader().packetId());
                addv(sessionStore, "hasWillMessage", true);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        return sessionStore;
    }


    public static ChannelSession mapTransToPublishMsgBeta(Map store) {
        ChannelSession channelSession = new ChannelSession();
        if ((Boolean) store.getOrDefault("hasWillMessage", Boolean.FALSE)) {
            byte[] payloads = Base64.getDecoder().decode((String) store.get("payload"));
            ByteBuf buf = null;
            try {
                buf = Unpooled.wrappedBuffer(payloads);
                MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(
                        MqttMessageType.valueOf((Integer) store.get("messageType")),
                        (Boolean) store.get("isDup"),
                        MqttQoS.valueOf((Integer) store.get("qosLevel")),
                        (Boolean) store.get("isRetain"),
                        (Integer) store.get("remainingLength"));

                MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader((String) store.get("topicName"),
                        (Integer) store.get("packetId"));
                MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader, mqttPublishVariableHeader, buf);
                channelSession.setWillMessage(mqttPublishMessage);
            } finally {
                if (buf != null) {
                    buf.release();
                }
            }
        }
        channelSession.setChannelId((String) store.get("channelId"));
        channelSession.setClientId((String) store.get("clientId"));
        channelSession.setCleanSession((Boolean) store.get("cleanSession"));
        channelSession.setBrokerId(String.valueOf(store.get("brokerId")));
        channelSession.setExpire((Integer) store.get("expire"));
        return channelSession;
    }


    private static void addv(Map<String, Object> map, String key, Object value) {
        Object obj = map.get(key);
        if (null == obj) {
            map.put(key, value);
            return;
        }
        if (obj instanceof Collection<?>) {
            ((Collection<Object>) obj).add(value);
            return;
        }
        List<Object> list = new ArrayList<>();
        list.add(obj);
        list.add(value);
        map.put(key, list);
    }
}
